/************************************************
 * Author       :   XXY
 * Blog         :   https://www.cnblogs.com/jzyl
 * Gitee        :   https://gitee.com/xiaobaichong
 * Email        :   1047185209@QQ.com
 * FileName     :   CryptogramUtility.cs
 * CreateData   :   2024/1/2 22:28:22
 * UnityVersion :   2021.3.30f1c1
 * Description  :   密码;密报;加密解密;明文密文
************************************************/

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace Main
{
    /*
     * 对称加密即  ：含有一个称为密钥的东西，在消息发送前使用密钥对消息进行加密，在对方收到消息之后，使用相同的密钥进行解密
     *
     * 非对称加密即：加密和解密使用不同的密钥的一类加密算法。
     *               这类加密算法通常有两个密钥A和B，使用密钥A加密数据得到的密文，只有密钥B可以进行解密操作（即使密钥A也无法解密），
     *               相反，使用了密钥B加密数据得到的密文，只有密钥A可以解密。
     *               这两个密钥分别称为私钥和公钥，顾名思义，私钥就是你个人保留，不能公开的密钥，而公钥则是公开给加解密操作的另一方的。
     *               根据不同用途，对数据进行加密所使用的密钥也不相同（有时用公钥加密，私钥解密；有时相反用私钥加密，公钥解密）。
     *               非对称加密的代表算法是RSA算法。
    */
    public static class CryptogramUtility
    {
        #region MD5     (MD5 是不可逆的，无法通过解密来获得原始数据)
        /// <summary>
        /// 16位MD5加密
        /// </summary>
        /// <param name="data">被加密数据</param>
        /// <param name="uppercase">是否大写</param>
        /// <returns></returns>
        public static string MD5Encrypt16(string data, bool uppercase = false)
        {
            using (MD5 md5 = MD5.Create())
            {
                byte[] inputBytes = Encoding.UTF8.GetBytes(data);
                byte[] hashBytes = md5.ComputeHash(inputBytes);

                // 将字节数组转换为16位表示
                StringBuilder sb = new StringBuilder();
                for (int i = 4; i < 12; i++)
                {
                    if (uppercase)
                    {
                        sb.Append(hashBytes[i].ToString("X2"));
                    }
                    else
                    {
                        sb.Append(hashBytes[i].ToString("x2"));
                    }
                }
                return sb.ToString();
            }
        }
        /// <summary>
        /// 32位MD5加密
        /// </summary>
        /// <param name="data">被加密数据</param>
        /// <param name="uppercase">是否大写</param>
        /// <returns></returns>
        public static string MD5Encrypt32(string data, bool uppercase = false)
        {
            using (MD5 md5 = MD5.Create())
            {
                byte[] inputBytes = Encoding.UTF8.GetBytes(data);
                byte[] hashBytes = md5.ComputeHash(inputBytes);

                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < hashBytes.Length; i++)
                {
                    if (uppercase)
                    {
                        sb.Append(hashBytes[i].ToString("X2"));
                    }
                    else
                    {
                        sb.Append(hashBytes[i].ToString("x2"));
                    }
                }
                return sb.ToString();
            }
        }
        #endregion

        #region SHA     (SHA加密算法与MD5加密类似，都是不可逆的，只是算法不同)
        /// <summary>
        /// SHA1 加密 
        /// </summary>
        /// <param name="data">被加密数据</param>
        /// <param name="uppercase">是否大写</param>
        /// <returns></returns>
        public static string SHA1Encrypt(string data, bool uppercase = false)
        {
            try
            {
                byte[] inputBytes = Encoding.UTF8.GetBytes(data);       //用指定编码转为bytes数组
                byte[] hashBytes = SHA1.Create().ComputeHash(inputBytes);
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < hashBytes.Length; i++)
                {
                    if (uppercase)
                    {
                        sb.Append(hashBytes[i].ToString("X2"));
                    }
                    else
                    {
                        sb.Append(hashBytes[i].ToString("x2"));
                    }
                }
                return sb.ToString();
            }
            catch (Exception ex)
            {
                return "SHA1加密出错：" + ex.Message;
            }
        }
        /// <summary>
        /// SHA256加密
        /// </summary>
        /// <param name="data">被加密数据</param>
        /// <param name="uppercase">是否大写</param>
        /// <returns></returns>
        public static string SHA256Encrypt(string data, bool uppercase = false)
        {
            try
            {
                byte[] inputBytes = Encoding.UTF8.GetBytes(data);       //用指定编码转为bytes数组
                byte[] hashBytes = SHA256.Create().ComputeHash(inputBytes);
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < hashBytes.Length; i++)
                {
                    if (uppercase)
                    {
                        sb.Append(hashBytes[i].ToString("X2"));
                    }
                    else
                    {
                        sb.Append(hashBytes[i].ToString("x2"));
                    }
                }
                return sb.ToString();
            }
            catch (Exception ex)
            {
                return "SHA256加密出错：" + ex.Message;
            }
        }
        /// <summary>
        /// SHA384加密
        /// </summary>
        /// <param name="data">被加密数据</param>
        /// <param name="uppercase">是否大写</param>
        /// <returns></returns>
        public static string SHA384Encrypt(string data, bool uppercase = false)
        {
            try
            {
                byte[] inputBytes = Encoding.UTF8.GetBytes(data);       //用指定编码转为bytes数组
                byte[] hashBytes = SHA384.Create().ComputeHash(inputBytes);
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < hashBytes.Length; i++)
                {
                    if (uppercase)
                    {
                        sb.Append(hashBytes[i].ToString("X2"));
                    }
                    else
                    {
                        sb.Append(hashBytes[i].ToString("x2"));
                    }
                }
                return sb.ToString();
            }
            catch (Exception ex)
            {
                return "SHA384加密出错：" + ex.Message;
            }
        }
        /// <summary>
        /// SHA512加密
        /// </summary>
        /// <param name="data">被加密数据</param>
        /// <param name="uppercase">是否大写</param>
        /// <returns></returns>
        public static string SHA512Encrypt(string data, bool uppercase = false)
        {
            try
            {
                byte[] inputBytes = Encoding.UTF8.GetBytes(data);       //用指定编码转为bytes数组
                byte[] hashBytes = SHA512.Create().ComputeHash(inputBytes);
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < hashBytes.Length; i++)
                {
                    if (uppercase)
                    {
                        sb.Append(hashBytes[i].ToString("X2"));
                    }
                    else
                    {
                        sb.Append(hashBytes[i].ToString("x2"));
                    }
                }
                return sb.ToString();
            }
            catch (Exception ex)
            {
                return "SHA512加密出错：" + ex.Message;
            }
        }
        #endregion

        #region HMAC    (这是不可逆的，就像所有形式的加密哈希一样。)
        /// <summary>
        /// HMAC MD5加密
        /// </summary>
        /// <param name="data">被加密数据</param>
        /// <param name="key">密钥</param>
        /// <param name="uppercase">是否大写</param>
        /// <returns></returns>
        public static string HMACMD5Encrypt(string data, string key, bool uppercase = false)
        {
            HMACMD5 hmacmd5 = new HMACMD5();
            hmacmd5.Key = System.Text.Encoding.UTF8.GetBytes(key);

            byte[] dataBuffer = System.Text.Encoding.UTF8.GetBytes(data);
            byte[] hashBytes = hmacmd5.ComputeHash(dataBuffer);

            StringBuilder sb = new StringBuilder();
            foreach (byte iByte in hashBytes)
            {
                if (uppercase)
                {
                    sb.AppendFormat("{0:X2}", iByte);
                }
                else
                {
                    sb.AppendFormat("{0:x2}", iByte);
                }
            }
            return sb.ToString();
        }
        /// <summary>
        /// HMAC SHA1加密
        /// </summary>
        /// <param name="data">被加密数据</param>
        /// <param name="key">密钥</param>
        /// <param name="uppercase">是否大写</param>
        /// <returns></returns>
        public static string HMACSHA1Encrypt(string data, string key, bool uppercase = false)
        {
            HMACSHA1 hmacsha1 = new HMACSHA1();
            hmacsha1.Key = System.Text.Encoding.UTF8.GetBytes(key);

            byte[] dataBuffer = System.Text.Encoding.UTF8.GetBytes(data);
            byte[] hashBytes = hmacsha1.ComputeHash(dataBuffer);

            StringBuilder sb = new StringBuilder();
            foreach (byte iByte in hashBytes)
            {
                if (uppercase)
                {
                    sb.AppendFormat("{0:X2}", iByte);
                }
                else
                {
                    sb.AppendFormat("{0:x2}", iByte);
                }
            }
            return sb.ToString();
        }
        /// <summary>
        /// HMAC SHA256加密
        /// </summary>
        /// <param name="data">被加密数据</param>
        /// <param name="key">密钥</param>
        /// <param name="uppercase">是否大写</param>
        /// <returns></returns>
        public static string HMACSHA256Encrypt(string data, string key, bool uppercase = false)
        {
            HMACSHA256 hmacsha256 = new HMACSHA256();
            hmacsha256.Key = System.Text.Encoding.UTF8.GetBytes(key);

            byte[] dataBuffer = System.Text.Encoding.UTF8.GetBytes(data);
            byte[] hashBytes = hmacsha256.ComputeHash(dataBuffer);

            StringBuilder sb = new StringBuilder();
            foreach (byte iByte in hashBytes)
            {
                if (uppercase)
                {
                    sb.AppendFormat("{0:X2}", iByte);
                }
                else
                {
                    sb.AppendFormat("{0:x2}", iByte);
                }
            }
            return sb.ToString();
        }
        /// <summary>
        /// HMAC SHA384加密
        /// </summary>
        /// <param name="data">被加密数据</param>
        /// <param name="key">密钥</param>
        /// <param name="uppercase">是否大写</param>
        /// <returns></returns>
        public static string HMACSHA384Encrypt(string data, string key, bool uppercase = false)
        {
            HMACSHA384 hmacsha384 = new HMACSHA384();
            hmacsha384.Key = System.Text.Encoding.UTF8.GetBytes(key);

            byte[] dataBuffer = System.Text.Encoding.UTF8.GetBytes(data);
            byte[] hashBytes = hmacsha384.ComputeHash(dataBuffer);

            StringBuilder sb = new StringBuilder();
            foreach (byte iByte in hashBytes)
            {
                if (uppercase)
                {
                    sb.AppendFormat("{0:X2}", iByte);
                }
                else
                {
                    sb.AppendFormat("{0:x2}", iByte);
                }
            }
            return sb.ToString();
        }
        /// <summary>
        /// HMAC SHA512加密
        /// </summary>
        /// <param name="data">被加密数据</param>
        /// <param name="key">密钥</param>
        /// <param name="uppercase">是否大写</param>
        /// <returns></returns>
        public static string HMACSHA512Encrypt(string data, string key, bool uppercase = false)
        {
            HMACSHA512 hmacsha512 = new HMACSHA512();
            hmacsha512.Key = System.Text.Encoding.UTF8.GetBytes(key);

            byte[] dataBuffer = System.Text.Encoding.UTF8.GetBytes(data);
            byte[] hashBytes = hmacsha512.ComputeHash(dataBuffer);

            StringBuilder sb = new StringBuilder();
            foreach (byte iByte in hashBytes)
            {
                if (uppercase)
                {
                    sb.AppendFormat("{0:X2}", iByte);
                }
                else
                {
                    sb.AppendFormat("{0:x2}", iByte);
                }
            }
            return sb.ToString();
        }
        /// <summary>
        /// HMAC REPEMD160加密
        /// </summary>
        /// <param name="data">被加密数据</param>
        /// <param name="key">密钥</param>
        /// <param name="uppercase">是否大写</param>
        /// <returns></returns>
        public static string HMACREPEMD160Encrypt(string data, string key, bool uppercase = false)
        {
            HMACRIPEMD160 hmacrepemd160 = new HMACRIPEMD160();
            hmacrepemd160.Key = System.Text.Encoding.UTF8.GetBytes(key);

            byte[] dataBuffer = System.Text.Encoding.UTF8.GetBytes(data);
            byte[] hashBytes = hmacrepemd160.ComputeHash(dataBuffer);

            StringBuilder sb = new StringBuilder();
            foreach (byte iByte in hashBytes)
            {
                if (uppercase)
                {
                    sb.AppendFormat("{0:X2}", iByte);
                }
                else
                {
                    sb.AppendFormat("{0:x2}", iByte);
                }
            }
            return sb.ToString();
        }
        #endregion

        #region Base64 加密解密
        /// <summary>
        /// Base 64 加密
        /// </summary>
        /// <param name="plainText">明文</param>
        /// <returns>密文</returns>
        public static string Base64Encrypt(string plainText)
        {
            UTF8Encoding utf8 = new UTF8Encoding();
            return Convert.ToBase64String(utf8.GetBytes(plainText));
        }
        /// <summary>
        /// Base64 解密
        /// </summary>
        /// <param name="cipherText">密文</param>
        /// <returns>明文</returns>
        public static string Base64Decrypt(string cipherText)
        {
            UTF8Encoding utf8 = new UTF8Encoding();
            return utf8.GetString(Convert.FromBase64String(cipherText));
        }
        #endregion

        #region AES 加密解密    (密文=明文+密钥+向量；明文=密文-密钥-向量)   密钥固定长度：128bits（16字节）
        /// <summary>
        /// AES 加密
        /// </summary>
        /// <param name="plainText">明文</param>
        /// <param name="key">密钥(128位)</param>
        /// <param name="mode">加密模式</param>
        /// <returns>密文</returns>
        public static string AESEncrypt(string plainText, string key, CipherMode mode = CipherMode.CBC)
        {
            byte[] IV = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF, 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF }; // 16位字符的密钥字符串
            key += "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
            char[] keychar = key.ToCharArray(0, 16);
            byte[] Key = Encoding.UTF8.GetBytes(keychar);
            byte[] encrypted;

            // Create an Aes object
            // with the specified key and IV.
            using (Aes aesAlg = Aes.Create())
            {
                aesAlg.Key = Key;
                aesAlg.IV = IV;
                aesAlg.Mode = mode;

                // Create an encryptor to perform the stream transform.
                ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);

                // Create the streams used for encryption.
                using (MemoryStream msEncrypt = new MemoryStream())
                {
                    using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                    {
                        using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                        {
                            //Write all data to the stream.
                            swEncrypt.Write(plainText);
                        }
                        encrypted = msEncrypt.ToArray();
                    }
                }
            }

            // Return the encrypted bytes from the memory stream.
            return Convert.ToBase64String(encrypted);
        }
        /// <summary>
        /// AES 解密
        /// </summary>
        /// <param name="cipherText">密文</param>
        /// <param name="key">密钥(128位)</param>
        /// <param name="mode">解密模式</param>
        /// <returns>明文</returns>
        public static string AESDecrypt(string cipherText, string key, CipherMode mode = CipherMode.CBC)
        {
            byte[] IV = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF, 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF }; // 16位字符的密钥字符串
            key += "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
            char[] keychar = key.ToCharArray(0, 16);
            byte[] Key = Encoding.UTF8.GetBytes(keychar);
            // Declare the string used to hold
            // the decrypted text.
            string plaintext = null;

            // Create an Aes object
            // with the specified key and IV.
            using (Aes aesAlg = Aes.Create())
            {
                aesAlg.Key = Key;
                aesAlg.IV = IV;
                aesAlg.Mode = mode;

                // Create a decryptor to perform the stream transform.
                ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);

                // Create the streams used for decryption.
                using (MemoryStream msDecrypt = new MemoryStream(Convert.FromBase64String(cipherText)))
                {
                    using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                    {
                        using (StreamReader srDecrypt = new StreamReader(csDecrypt))
                        {
                            // Read the decrypted bytes from the decrypting stream
                            // and place them in a string.
                            plaintext = srDecrypt.ReadToEnd();
                        }
                    }
                }
            }

            return plaintext;
        }
        #endregion

        #region DES 加密解密     (提供了较新的对称加密算法，即高级加密标准 (AES) 。 请考虑使用 Aes 类而不是 DES 类。 )   密钥固定长度：64bits（8字节）
        /// <summary>
        /// DES 加密
        /// </summary>
        /// <param name="plainText">明文</param>
        /// <param name="key">密钥(64位)</param>
        /// <param name="mode">加密模式</param>
        /// <returns>密文</returns>
        public static string DESEncrypt(string plainText, string key, CipherMode mode = CipherMode.CBC)
        {
            byte[] IV = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF }; // 8位字符的密钥字符串
            key += "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
            char[] keychar = key.ToCharArray(0, 8);
            byte[] Key = Encoding.ASCII.GetBytes(keychar);

            DESCryptoServiceProvider cryptoProvider = new DESCryptoServiceProvider();
            cryptoProvider.Mode = mode;
            int i = cryptoProvider.KeySize;
            MemoryStream ms = new MemoryStream();
            CryptoStream cst = new CryptoStream(ms, cryptoProvider.CreateEncryptor(Key, IV), CryptoStreamMode.Write);

            StreamWriter sw = new StreamWriter(cst);
            sw.Write(plainText);
            sw.Flush();
            cst.FlushFinalBlock();
            sw.Flush();
            return Convert.ToBase64String(ms.GetBuffer(), 0, (int)ms.Length);
        }

        /// <summary>
        /// DES 解密
        /// </summary>
        /// <param name="cipherText">密文</param>
        /// <param name="key">密钥(64位)</param>
        /// <param name="mode">加密模式</param>
        /// <returns>明文</returns>
        public static string DESDecrypt(string cipherText, string key, CipherMode mode = CipherMode.CBC)
        {
            byte[] IV = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF }; // 8位字符的密钥字符串
            key += "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
            char[] keychar = key.ToCharArray(0, 8);
            byte[] Key = Encoding.ASCII.GetBytes(keychar);

            byte[] byEnc = Convert.FromBase64String(cipherText);
            DESCryptoServiceProvider cryptoProvider = new DESCryptoServiceProvider();
            cryptoProvider.Mode = mode;
            MemoryStream ms = new MemoryStream(byEnc);
            CryptoStream cst = new CryptoStream(ms, cryptoProvider.CreateDecryptor(Key, IV), CryptoStreamMode.Read);
            StreamReader sr = new StreamReader(cst);
            return sr.ReadToEnd();
        }
        #endregion

        #region TripleDes 加密解密   (提供了较新的对称加密算法，即高级加密标准 (AES) 。 请考虑使用 Aes 类及其派生类而不是 TripleDES 类。)

        #endregion

        #region RSA 加密解密
        /// <summary>
        /// RSA 算法生成 XML格式 密钥和公钥
        /// </summary>
        /// <param name="privateXMLKeys">XML格式 私钥</param>
        /// <param name="publicXMLKey">XML格式 公钥</param>
        /// <param name="keySize">密钥长度：<c>512倍数 </c> 密钥越长耗时越大</param>
        public static void RSAXMLKey(out string privateXMLKeys, out string publicXMLKey, int keySize = 1024)
        {
            using (var rsa = new RSACryptoServiceProvider(keySize))
            {
                // 私钥
                privateXMLKeys = rsa.ToXmlString(true);
                // 公钥
                publicXMLKey = rsa.ToXmlString(false);
            }
        }
        /// <summary>
        /// RAS 加密
        /// </summary>
        /// <param name="plainText">明文</param>
        /// <param name="publicXMLKeys">公钥</param>
        /// <returns>密文</returns>
        static string RSAEncrypt(string plainText, string publicXMLKeys)
        {
            byte[] bytes = Encoding.UTF8.GetBytes(plainText);
            using (RSA rsa = RSA.Create())
            {
                rsa.FromXmlString(publicXMLKeys);
                byte[] bytes1 = rsa.Encrypt(bytes, RSAEncryptionPadding.Pkcs1);
                return Convert.ToBase64String(bytes1);
            }
        }

        /// <summary>
        /// RAS 解密
        /// </summary>
        /// <param name="cipherText">密文</param>
        /// <param name="privateXMLKey">私钥</param>
        /// <returns>明文</returns>
        static string RSADecrypt(string cipherText, string privateXMLKey)
        {
            byte[] bytes = Convert.FromBase64String(cipherText);
            using (RSA rsa = RSA.Create())
            {
                rsa.FromXmlString(privateXMLKey);
                byte[] decryptedData = rsa.Decrypt(bytes, RSAEncryptionPadding.Pkcs1);
                return Encoding.UTF8.GetString(decryptedData);
            }
        }
        #endregion

        #region DSA 加密解密

        #endregion

        #region Rabbit 加密解密

        #endregion

        #region Hash 加密解密

        #endregion
    }
}